﻿#pragma once
#include <algorithm>
#include "Direct_All.h"
#include "Math.h"
using namespace Math;

class D3D_UI
{
protected:
	UINT						status;
	LPDIRECT3DTEXTURE9			sleep,activ,down;
	LPDIRECT3DVERTEXBUFFER9		g_pVB;
	D3DXVECTOR3					MousePos;
	bool						enable;
	time_t						timer;
	bool						(*function)(LPVOID);

public:
	D3DRectangle				Rectangle;
	bool						Down;

	D3D_UI(){status=0;}
	D3D_UI(LPDIRECT3DDEVICE9 &pd3dDevice,
										bool  (*func)(LPVOID),
										LPCWSTR sleep_,
										LPCWSTR activ_,
										LPCWSTR down_, 
										float x1, 
										float y1, 
										float z1, 
										float x2,
										float y2,
										float z2,
										float z3,
										float z4)
	{
		UpdateObject(pd3dDevice, sleep_, activ_, down_, x1, y1, z1, x2, y2, z2, z3, z4);

		function	=	func;
		UINT			size	=	6;


		CUSTOMVERTEX	*g_Vertices =	Rectangle.init();

		if(g_pVB!=NULL) g_pVB->Release();

		pd3dDevice->CreateVertexBuffer(
			size * sizeof(CUSTOMVERTEX),
			D3DUSAGE_DYNAMIC,
			D3DFVF_CUSTOMVERTEX,
			D3DPOOL_DEFAULT,
			&g_pVB,
			NULL );

		VOID* pVertices;
		g_pVB->Lock( 0, size * sizeof(CUSTOMVERTEX), (void**)&pVertices, 0 );
		memcpy( pVertices, g_Vertices, size * sizeof(CUSTOMVERTEX) );
		g_pVB->Unlock();

		delete g_Vertices,pVertices;		
	}

	static void TransformCoords(LPDIRECT3DDEVICE9 &pd3dDevice, 
								D3DCamera &Camera, 
								D3DXMATRIX &Transform, 
								D3DXVECTOR3 &pos, 
								D3DXVECTOR3 &dir, 
								int x, 
								int y)
	{
		float						px,
									py;

		D3DVIEWPORT9				ViewPort;
		D3DXMATRIX					MatrixProjection;

		pd3dDevice->GetViewport		(&ViewPort);
		pd3dDevice->GetTransform	(D3DTS_PROJECTION, &MatrixProjection);

		px		=	((( 2.0f*(float)x) / (float)ViewPort.Width)  - 1.0f) / MatrixProjection._11;
		py		=	(((-2.0f*(float)y) / (float)ViewPort.Height) + 1.0f) / MatrixProjection._22;

		pos.x	=	Camera.CamPos.x; 
		pos.y	=	Camera.CamPos.y; 
		pos.z	=	Camera.CamPos.z;
  
		dir.x	=	px; 
		dir.y	=	py; 
		dir.z	=	1.0;

		D3DXVec3TransformCoord( 
		  &pos, 
		  &pos, 
		  &Transform 
		); 
  
		D3DXVec3TransformNormal( 
		  &dir, 
		  &dir, 
		  &Transform 
		);
	}
	
	
	void clickUp(LPVOID Object)
	{
		if(status == 2) function((LPVOID)Object);
		SetTimer(100);
	}
	
	virtual void MouseMove(bool select, LPVOID Object)
	{
		if(select)
		{
			if(!Down)
				setStatus(1); //Active
		}
		else
			setStatus(0); //Sleep
	}
	virtual void MouseDown()
	{
		setStatus(2); //Down
		Down	=	true;
	}
	virtual void MouseUp(bool select, LPVOID Object)
	{
		if(select)
		{
			clickUp(Object);
			Down = false;
			setStatus(1); //Active
		}
		else
		{
			if(Down)
			{
				setStatus(0);
				Down = false;
			}
		}
	}
	virtual bool Select(D3DXVECTOR3 &pos, D3DXVECTOR3 &dir)
	{
		float				Distance	=	2000.0f;

		CUSTOMVERTEX		*buffer		=	Rectangle.init();

		bool				Result_1	=	false,
							Result_2	=	false;

		

		Result_1	=	 D3DXIntersectTri	(	&D3DXVECTOR3(buffer[0].x, buffer[0].y, buffer[0].z), 
												&D3DXVECTOR3(buffer[1].x, buffer[1].y, buffer[1].z),
												&D3DXVECTOR3(buffer[2].x, buffer[2].y, buffer[2].z),
												&pos,
												&dir,
												0,
												0,
												&Distance);
		if(Result_1)
			MousePos = Math::GetPoint_Vector_Length(pos, dir, Distance);

		Result_2	=	 D3DXIntersectTri	(	&D3DXVECTOR3(buffer[3].x, buffer[3].y, buffer[3].z), 
												&D3DXVECTOR3(buffer[4].x, buffer[4].y, buffer[4].z),
												&D3DXVECTOR3(buffer[5].x, buffer[5].y, buffer[5].z),
												&pos,
												&dir,
												0,
												0,
												&Distance);
		if(Result_2)
			MousePos = Math::GetPoint_Vector_Length(pos, dir, Distance);

		return Result_1 || Result_2;
	}
	void SetTimer(UINT t_size)
	{
		timer	=	clock() + t_size;
	}
	void SetLight(LPDIRECT3DDEVICE9 &pd3dDevice, bool Light_Enable)
	{
		pd3dDevice->SetRenderState			(D3DRS_LIGHTING,			Light_Enable);
	}
	void UpdateObject(LPDIRECT3DDEVICE9 &pd3dDevice, 
										LPCWSTR sleep_,
										LPCWSTR activ_,
										LPCWSTR down_, 
										float x1, 
										float y1, 
										float z1, 
										float x2,
										float y2,
										float z2,
										float z3,
										float z4)
	{
		Down		= false;
		status		= 0;
		g_pVB		=	NULL;
		sleep		=	NULL;
		activ		=	NULL;
		down		=	NULL;
		D3DXCreateTextureFromFile(pd3dDevice,sleep_, &sleep);
		D3DXCreateTextureFromFile(pd3dDevice,activ_, &activ);
		D3DXCreateTextureFromFile(pd3dDevice,down_ , &down);
		Rectangle	= *new D3DRectangle(x1, y1, z1, x2, y2, z2, z3, z4);
	}

	virtual LPDIRECT3DTEXTURE9 getTexture()
	{
		if(status == 0) return sleep;
		if(status == 1) return activ;
		if(status == 2) return down;
		return sleep;
	}
	virtual bool Render(LPDIRECT3DDEVICE9 &pd3dDevice, bool Light_Enable)	= 0;
	virtual void setStatus(int newstatus)									= 0;
	
};
class D3DXButton : public D3D_UI
{
public:

	D3DXButton(	LPDIRECT3DDEVICE9	&pd3dDevice, 
				bool				(*func)(LPVOID),
				LPCWSTR				sleep_,
				LPCWSTR				activ_,
				LPCWSTR				down_, 
				float				x1, 
				float				y1, 
				float				z1, 
				float				x2,
				float				y2,
				float				z2,
				float				z3,
				float				z4) : D3D_UI (	pd3dDevice,
													func,
													sleep_,
													activ_,
													down_,
													x1,
													y1,
													z1,
													x2,
													y2,
													z2,
													z3,
													z4)
	{
			
	}

	void setStatus(int newstatus)
	{
		if(timer > clock())				return;
		if(newstatus<0 || newstatus>2)	return;
		status	=	newstatus;
	}

	bool Render(LPDIRECT3DDEVICE9 &pd3dDevice, bool Light_Enable)
	{
		SetLight(pd3dDevice, Light_Enable);

		pd3dDevice->SetFVF				( D3DFVF_CUSTOMVERTEX );
		pd3dDevice->SetStreamSource		( 0, g_pVB, 0, sizeof(CUSTOMVERTEX));

		if(FAILED(pd3dDevice->SetTexture	(0,	getTexture())))				return false;
		if(FAILED(pd3dDevice->DrawPrimitive	(D3DPT_TRIANGLELIST, 0, 2)))	return false;

		return true;
	}

	~D3DXButton()
	{
	}
};
class D3DXCheckButton_Thread : public D3D_UI
{
private:
	HANDLE			Proc;

	static DWORD WINAPI ThreadFunc(LPVOID pvPararn) 
	{ 
		DWORD rtwResult = 0; 

		#define			my__type		((pair<LPVOID, D3DXCheckButton_Thread*>*)pvPararn)

		while(my__type -> second -> Down)
		{
			my__type -> second -> function((LPVOID) my__type -> first);
			//Sleep(5);
		}
		
		return(rtwResult); 
	} 

public:

	D3DXCheckButton_Thread(LPDIRECT3DDEVICE9	&pd3dDevice, 
				bool				(*func)(LPVOID),
				LPCWSTR				sleep_,
				LPCWSTR				activ_,
				LPCWSTR				down_, 
				float				x1, 
				float				y1, 
				float				z1, 
				float				x2,
				float				y2,
				float				z2,
				float				z3,
				float				z4) : D3D_UI (	pd3dDevice,
													func,
													sleep_,
													activ_,
													down_,
													x1,
													y1,
													z1,
													x2,
													y2,
													z2,
													z3,
													z4)
	{
			
	}
	void clickUp(LPVOID Object)
	{
		if(Down)
		{
			pair<LPVOID, D3DXCheckButton_Thread*>				*Two;
			Two = new pair<LPVOID, D3DXCheckButton_Thread*>		(Object, this);

			Proc = CreateThread (NULL, NULL, ThreadFunc, Two, NULL, NULL);
			SetThreadAffinityMask(Proc, 10);
			SetTimer(100);
		}
	}
	void setStatus(int newstatus)
	{
		if(timer > clock())				return;
		if(newstatus<0 || newstatus>2)	return;
		status	=	newstatus;
	}
	void MouseMove(bool select, LPVOID Object)
	{
		if(!Down)
			D3D_UI::MouseMove(select, Object);
	}
	void MouseDown()
	{

	}
	void MouseUp(bool select, LPVOID Object)
	{
		if(select)
			if(Down)
			{
				Down = false;
				setStatus(1);
			}
			else
			{
				Down = true;
				setStatus(2);
				clickUp(Object);
				SetTimer(100);
			}
	}
	bool Render(LPDIRECT3DDEVICE9 &pd3dDevice, bool Light_Enable)
	{
		SetLight(pd3dDevice, Light_Enable);

		pd3dDevice->SetFVF				( D3DFVF_CUSTOMVERTEX );
		pd3dDevice->SetStreamSource		( 0, g_pVB, 0, sizeof(CUSTOMVERTEX));

		if(FAILED(pd3dDevice->SetTexture	(0,	getTexture())))				return false;
		if(FAILED(pd3dDevice->DrawPrimitive	(D3DPT_TRIANGLELIST, 0, 2)))	return false;

		return true;
	}

	~D3DXCheckButton_Thread()
	{
	}
};

class D3DXScrollBar : public D3D_UI
{
private:
	D3DRectangle		RectangleO;

	float				cursor_position,
						cursor_height,
						cursor_width,
						cursor_H;

	LPDIRECT3DDEVICE9	*LPpd3dDevice;

public:
	D3DXScrollBar(	LPDIRECT3DDEVICE9	&pd3dDevice, 
					bool				(*func)(LPVOID),
					LPCWSTR				line,
					LPCWSTR				cursor_sleep,
					LPCWSTR				cursor_down,
					float				cursor_position_,
					float				cursor_height_,
					float				cursor_width_,
					float				cursor_H_,
					float				x1, 
					float				y1, 
					float				z1, 
					float				x2,
					float				y2,
					float				z2,
					float				z3,
					float				z4)
	{
		LPpd3dDevice	=	&pd3dDevice;

		cursor_position	=	cursor_position_;
		cursor_height	=	cursor_height_;
		cursor_width	=	cursor_width_;
		cursor_H		=	cursor_H_;

		UpdateObject(pd3dDevice, line, cursor_sleep, cursor_down, x1, y1, z1, x2, y2, z2, z3, z4);

		function	=	func;

		RectangleO = *new D3DRectangle(x1, y1, z1, x2, y2, z2, z3, z4);

		UpdateCursor(pd3dDevice);
	}

	bool Render(LPDIRECT3DDEVICE9 &pd3dDevice, bool Light_Enable)
	{
		SetLight(pd3dDevice, Light_Enable);

		pd3dDevice->SetFVF				( D3DFVF_CUSTOMVERTEX );
		pd3dDevice->SetStreamSource		( 0, g_pVB, 0, sizeof(CUSTOMVERTEX));

		if(FAILED(pd3dDevice->SetTexture	(0,	sleep)))					return false;
		if(FAILED(pd3dDevice->DrawPrimitive	(D3DPT_TRIANGLELIST, 0, 2)))	return false;
		if(FAILED(pd3dDevice->SetTexture	(0,	getTexture())))				return false;
		if(FAILED(pd3dDevice->DrawPrimitive	(D3DPT_TRIANGLELIST, 6, 2)))	return false;

		return true;
	}
	float getCursor_position()
	{
		return cursor_position;
	}
	void setStatus(int newstatus)
	{
		if(timer > clock())	return;
		if(newstatus == 1 )	return;
		status	=	newstatus;
		UpdateCursor(*LPpd3dDevice);
	}
	void MouseMove(bool select, LPVOID Object)
	{
		
			if(Down)
				clickUp(Object);
			else
				setStatus(0); //Sleep
	}

	LPDIRECT3DTEXTURE9 getTexture()
	{
		if(status == 0) return activ;
		if(status == 2) return down;
		return activ;
	}
	void UpdateCursor(LPDIRECT3DDEVICE9	&pd3dDevice)
	{
		UINT		size	=	6;

		CUSTOMVERTEX	*g_Vertices =	RectangleO.init();

		if(g_pVB!=NULL) g_pVB->Release();

		pd3dDevice->CreateVertexBuffer(
			size * 2 * sizeof(CUSTOMVERTEX),
			D3DUSAGE_DYNAMIC,
			D3DFVF_CUSTOMVERTEX,
			D3DPOOL_DEFAULT,
			&g_pVB,
			NULL );

		VOID* pVertices;

		g_pVB->Lock( 0, size * 2 * sizeof(CUSTOMVERTEX), (void**)&pVertices, 0 );

		memcpy_s(pVertices, size * sizeof(CUSTOMVERTEX), g_Vertices,  size * sizeof(CUSTOMVERTEX));	

		float		Q = status;
		if(Q == 0)	{Q = 1.5;}
		else		{Q = 1; SetTimer(10);}
		if(clock() - timer > 0)
			Q = 1.5;

		Rectangle =		D3DRectangle(	RectangleO.getx1() + abs(RectangleO.getx1()-RectangleO.getx2())/2 - cursor_width/Q, 
										RectangleO.gety2() + abs(RectangleO.gety1()-RectangleO.gety2())*cursor_position + cursor_height/Q, 
										RectangleO.getz1() - cursor_H, 
										RectangleO.getx1() + abs(RectangleO.getx1()-RectangleO.getx2())/2 + cursor_width/Q, 
										RectangleO.gety2() + abs(RectangleO.gety1()-RectangleO.gety2())*cursor_position - cursor_height/Q, 
										RectangleO.getz2() - cursor_H, 
										RectangleO.getz3() - cursor_H, 
										RectangleO.getz4() - cursor_H);
		g_Vertices = Rectangle.init();

		memcpy_s((CUSTOMVERTEX*)pVertices + size, size * sizeof(CUSTOMVERTEX), g_Vertices,  size * sizeof(CUSTOMVERTEX));

		g_pVB->Unlock();
		
		delete g_Vertices,pVertices;
	}
	bool Select(D3DXVECTOR3 &pos, D3DXVECTOR3 &dir)
	{
		if(!Down)
			return D3D_UI::Select(pos, dir);
		D3DXPLANE			Plane;
		D3DXPlaneFromPoints(&Plane, 
			&D3DXVECTOR3(RectangleO.getx1(), RectangleO.gety1(), RectangleO.getz1()),
			&D3DXVECTOR3(RectangleO.getx2(), RectangleO.gety2(), RectangleO.getz2()),
			&D3DXVECTOR3(RectangleO.getx1(), RectangleO.gety2(), RectangleO.getz3()));

		MousePos = GetPoint_Vector_ContactToSplane(Plane, pos, dir);

		return true;
	}


	void CursorMove()
	{
		cursor_position = (MousePos.y - RectangleO.getBestDown()) / abs(RectangleO.getBestDown() - RectangleO.getBestUp());
		if(cursor_position > 1.0f)
			cursor_position = 1.0f;
		if(cursor_position < 0.0f)
			cursor_position = 0.0f;
	}
};
